fix!: require merchant_authorization in AP2-active checkout responses#466
Conversation
The spec mandates the field in three places (ap2-mandates.md:112, 146, 216): "The business MUST include ap2.merchant_authorization in all checkout responses." But ap2_with_merchant_authorization had no `required` array, so schema-driven implementations could omit the field and validate clean — breaking the AP2 cryptographic chain silently: 1. Business signs the checkout → puts JWS in ap2.merchant_authorization 2. Platform verifies, issues SD-JWT+kb mandate covering the full checkout *including* merchant_authorization 3. Business later verifies the mandate, expecting its own signature embedded If step 1 omits merchant_authorization, step 2's mandate has nothing for the business to recognize in step 3, and the non-repudiation guarantee is gone. Matches the established response-only-required pattern in checkout.json (ucp/id/status/currency/totals/links: ucp_request=omit + listed in required). Breaking: AP2-active business responses that previously validated without merchant_authorization now fail schema validation. This is the intended behavior per spec; mock servers in the conformance suite may need a parallel update to include the field.
|
Source-read note: this looks directionally right, but I think it may only close the
That seems to leave the same AP2-active response gap described in the PR body: the docs say once Would it make sense to require |
Description
The spec mandates
ap2.merchant_authorizationin three places:ap2-mandates.md:112— "The business MUST includeap2.merchant_authorizationin all checkout responses."ap2-mandates.md:146-148- "Businesses MUST embed their signature in the checkout response body underap2.merchant_authorization..."ap2-mandates.md:216-218— "The checkout mandate MUST contain the full checkout response including theap2.merchant_authorizationfield."But
ap2_with_merchant_authorizationhad norequiredarray, so a response that omits the field validates clean. A spec-driven implementer ships a business that emits non-AP2-conformant responses, breaking the cryptographic chain at the platform's mandate-verification step — only discoverable when payment processors reject the mandate downstream.The chain works only if every link is present:
ap2.merchant_authorizationmerchant_authorizationOmitting step 1 makes step 3's verification fail by design.
Follows the established response-only-required pattern in
checkout.json(ucp,id,status,currency,totals,links— all combineucp_request: "omit"with inclusion in the parentrequiredarray).Category (Required)
Checklist
!for breaking changes).Screenshots / Logs (if applicable)
Local verification:
ucp-schema lint source/— 88 files passedscripts/validate_examples.py --schema-base source/schemas/— 253 passed, 0 failed (every existing AP2 spec example already includesmerchant_authorization)scripts/test_validate_examples.py— 43 passeducp-schema resolve ap2_mandate.json --response --op readconfirms the resolved response schema hasrequired: ["merchant_authorization"]ucp-schema resolve ap2_mandate.json --request --op createconfirms request variants still stripmerchant_authorizationcorrectly viaucp_request: "omit"Breaking-change note
AP2-active business responses that previously validated without
merchant_authorizationwill now fail schema validation. That is the intended behavior per spec. Downstream impact:ap2_test.py) primarily exercises the request side, so it should be unaffected; any mock business responses elsewhere that omitmerchant_authorizationwill need to add it.python-sdkregenerates Pydantic models from schemas, so the field becomes non-Optional on the next regen.